//
//  main.c
//  Socket
//
//  Created by wangrui on 15/4/14.
//  Copyright (c) 2015年 PPS. All rights reserved.
//

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>

void error(char *msg) {
    fprintf(stderr, "%s: %s\n", msg, strerror(0));
    exit(1);
}

/*
 * 仅有服务端程序存在时, 客服端使用：telnet 127.0.0.1 30000 连接
 */

int read_in(int socket, char *buf, int len) {
    char *s = buf;
    int slen = len;
    ssize_t c = recv(socket, s, slen, 0);
    while ((c>0) && (s[c-1] != '\n')) {
        s += c;
        slen -= c;
        c = recv(socket, s, slen, 0);
    }
    
    if (c < 0) {
        return (int)c;
    }
    else if (c==0) {
        buf[0] = '\0';
    }
    else
        s[c-1] = '\0';
    
    return len - slen;
}

/**
 *  @brief  服务端程序
 */
void startServer() {
    int listener_d = socket(PF_INET, SOCK_STREAM, 0);
    if (listener_d == -1) {
        error("Can't open socket");
    }
    
    struct sockaddr_in name;
    name.sin_family = PF_INET;
    name.sin_port = (in_port_t)htons(30000);
    name.sin_addr.s_addr = htonl(INADDR_ANY);
    
    //重用端口,防止重启程序不能绑定
    int reuse = 1;
    if (setsockopt(listener_d, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int)) == -1) {
        error("Can't set the reuse option on the socket");
    }
    
    int c = bind(listener_d, (struct sockaddr *)&name, sizeof(name));
    
    if (c==-1) {
        error("Can't bind to socket");
    }
    
    if (listen(listener_d, 10) == -1) { //10为一次性监听最大的客服端个数
        error("Can't listen");
    }
    
    char buf[255];
    
    while (1) {
        
        struct sockaddr_storage client_addr;
        unsigned int address_size = sizeof(client_addr);
        int connect_d = accept(listener_d, (struct sockaddr *)&client_addr, &address_size);
        
        if (connect_d == -1) {
            error("Can't open secondary socket");
        }
        
        ssize_t rc = recv(connect_d, buf, sizeof(buf), 0);
        printf("%s length:%zd\n",buf,rc);
        
        char *msg = "****************\n Internet Socket Server!\n Receieve Server Message!\n****************\n";
        
        if (send(connect_d, msg, strlen(msg), 0) == -1) {
            error("Send");
        }
        
        //从客服端接收消息
        read_in(connect_d, buf, sizeof(buf));
        
        printf("%s \n",buf);
        
        close(connect_d);
    }
}


/**
 *  @brief  客服端程序
 */
void startClient() {
    
    /*
        struct addrinfo *res;
        struct addrinfo hints;
        memset(&hints, 0, sizeof(hints));
        hints.ai_family = PF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        getaddrinfo("www.baidu.com", "80", &hints, &res);
        int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
     
        int c = connect(s, res->ai_addr, res->ai_addrlen);
        freeaddrinfo(res);
    */
    
    /**
     * 简单连接的写法
     */
    int s = socket(PF_INET, SOCK_STREAM, 0);

    if (s==-1) {
        error("Can't open scoket");
    }
    
    struct sockaddr_in si;
    memset(&si, 0, sizeof(si));
    si.sin_family = PF_INET;
    si.sin_addr.s_addr = inet_addr("127.0.0.1");
    si.sin_port = htons(30000);
    int c = connect(s, (struct sockaddr *)&si, sizeof(si));
    
    if (c==-1) {
        error("Can't connect to socket");
    }
    
    char *msg = "client send to server";
    ssize_t result = send(s, msg, strlen(msg), 0);
    
    if (result == -1) {
        error("Error talking to server");
    }
    
    char rec[256];
    ssize_t bytesRcvd = recv(s,rec,255,0);
    
    while (bytesRcvd) {
        
        if (bytesRcvd == -1) {
            error("Can't read from server");
        }
        
        rec[bytesRcvd] = '\0';
        
        printf("%s",rec);
        
        bytesRcvd = recv(s,rec,255,0);
    }
    
    close(s);
}


/**
 *  @brief  可分别打开两个工程进行断点调试
 */
int main(int argc, const char * argv[]) {
 
    startServer();
    
    return 0;
}
